package com.lsj.service.impl;

import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lsj.config.redis.RedisKey;
import com.lsj.core.exception.CustomerException;
import com.lsj.core.response.ResponseType;
import com.lsj.core.util.ExceptionHelperUtil;
import com.lsj.core.util.QueryHelperUtil;
import com.lsj.mapper.*;
import com.lsj.mapper.entity.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author:lin.sj
 * @Data:2021/7/6 13:39
 * @Desc: spring secirity动态加载用户实现类
 */
@Service
@CacheConfig(cacheNames = RedisKey.USER_KEY)
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    MySysRoleMapper mySysRoleMapper;
    @Autowired
    MySysMenuMapper mySysMenuMapper;
    @Autowired
    SysUserOrgMapper sysUserOrgMapper;
    @Autowired
    SysOrgMapper sysOrgMapper;

    /**
     * @Author: lin.sj
     * @Date: 2021/8/18 20:36
     * @Desc: 根据账户获取用户信息，并返回权限集合和组织机构等信息
     **/
    @Override
    @Cacheable(key = "#account")
    public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
        //根据账户查询
        LambdaQueryWrapper<SysUser> sysUserWhere = new LambdaQueryWrapper<>();
        sysUserWhere.eq(SysUser::getUsername,account);
        SysUser sysUser = sysUserMapper.selectOne(sysUserWhere);
        if(sysUser == null){
            throw new BadCredentialsException("用户名或密码错误");
        }

        //查询关联的角色
        List<SysRole> roles = mySysRoleMapper.findRoleByUserId(sysUser.getId());
        if(roles == null || roles.size()<=0){
            throw new CustomerException(ResponseType.error,"当前用户没有关联角色，无法登录");
        }
        List<String> roleCodes =  roles.stream().map(SysRole::getRoleCode).collect(Collectors.toList());

        //根据用户角色编码查询关联的权限信息
        List<String> authorities = mySysMenuMapper.findAuthorityByRoleCodes(roleCodes);

        //为角色标识加上ROLE_前缀（Spring Security规范）
        roleCodes = roleCodes.stream()
                .map(r -> "ROLE_"+r).collect(Collectors.toList());
        //角色是一种特殊的权限，可在鉴权规则中增加对角色的鉴权,所以合并
        authorities.addAll(roleCodes);
        //从实体类转换成security需要的userDeatil
        MyUserDetail myUserDetail = Convert.convert(MyUserDetail.class, sysUser);
        //设置用户权限
        myUserDetail.setAuthorities(
                //使用提供的工具类，以逗号为分隔符将字符串转换成权限列表
                AuthorityUtils.commaSeparatedStringToAuthorityList(
                        String.join(",",authorities)
                )
        );
        //查询关联的机构
        LambdaQueryWrapper<SysUserOrg> userOrgWhere = QueryHelperUtil.getLambdaWrapper(SysUserOrg.class);
        userOrgWhere.eq(SysUserOrg::getUserId,sysUser.getId());
        SysUserOrg sysUserOrg = sysUserOrgMapper.selectOne(userOrgWhere);
        ExceptionHelperUtil.nullObjException(sysUserOrg,"当前用户不存在关联的组织机构，无法登录！");
        SysOrg sysOrg = sysOrgMapper.selectById(sysUserOrg.getOrgId());
        myUserDetail.setSysOrg(sysOrg);
        return myUserDetail;
    }
}
